home *** CD-ROM | disk | FTP | other *** search
/ MACD 5 / MACD 5.bin / workbench / boot / czesc_2 / toolmanager / source / prefs / accesswindow.c next >
C/C++ Source or Header  |  1993-05-15  |  18KB  |  694 lines

  1. /*
  2.  * accesswindow.c  V2.1
  3.  *
  4.  * access edit window handling
  5.  *
  6.  * (c) 1990-1993 Stefan Becker
  7.  */
  8.  
  9. #include "ToolManagerConf.h"
  10.  
  11. /* Library for host requester */
  12. struct Library *EnvoyBase;
  13.  
  14. struct AccessNode {
  15.                    struct Node an_Node;
  16.                    struct List an_Entries;
  17.                   };
  18.  
  19. /* Window data */
  20. static struct Gadget *gl;             /* Gadget list */
  21. static struct Window *w;              /* Window */
  22. static struct MsgPort *wp;            /* Window user port */
  23. static UWORD ww,wh;                   /* Window size */
  24. static struct AccessNode *CurrentNode;
  25. static struct Node *CurrentEntry;
  26. static LONG CurrentTop;               /* Top tool ordinal number */
  27. static LONG CurrentOrd;               /* Current tool ordinal number */
  28. static BOOL ReqOpen;
  29. static struct Requester DummyReq;
  30. #define WINDOW_IDCMP (IDCMP_CLOSEWINDOW|IDCMP_REFRESHWINDOW|BUTTONIDCMP|\
  31.                       LISTVIEWIDCMP|IDCMP_VANILLAKEY)
  32.  
  33. /* Gadget data */
  34. #define GAD_NAME_BUT 0
  35. #define GAD_NAME_TXT 1
  36. #define GAD_NAME_STR 2
  37. #define GAD_ENTRIES  3
  38. #define GAD_ADD      4
  39. #define GAD_REMOVE   5
  40. #define GAD_OK       6
  41. #define GAD_CANCEL   7
  42. #define GADGETS      8
  43. static struct GadgetData gdata[GADGETS];
  44.  
  45. /* Gadget tags */
  46. static struct TagItem nametags[]={GTST_String,   NULL,
  47.                                   GTST_MaxChars, SGBUFLEN,
  48.                                   TAG_DONE};
  49.  
  50. static struct TagItem lvtags[]={GTLV_Labels,       NULL,
  51.                                 GTLV_ShowSelected, NULL,
  52.                                 TAG_DONE};
  53.  
  54. /* Gadget vanilla key data */
  55. #define KEY_NAME   0
  56. #define KEY_ADD    1
  57. #define KEY_OK     2
  58. #define KEY_CANCEL 3
  59. static char KeyArray[KEY_CANCEL+1];
  60.  
  61. /* Init access edit window */
  62. void InitAccessEditWindow(UWORD left, UWORD fheight)
  63. {
  64.  ULONG i,tmp,maxw1,maxw2;
  65.  ULONG strheight=fheight+2;
  66.  struct GadgetData *gd;
  67.  
  68.  /* Init strings */
  69.  gdata[GAD_NAME_TXT].name=AppStrings[MSG_WINDOW_NAME_GAD];
  70.  gdata[GAD_ENTRIES].name =AppStrings[MSG_ACCESSWIN_ENTRIES_GAD];
  71.  gdata[GAD_ADD].name     =AppStrings[MSG_ACCESSWIN_ADD_GAD];
  72.  gdata[GAD_REMOVE].name  =AppStrings[MSG_WINDOW_REMOVE_GAD];
  73.  gdata[GAD_OK].name      =AppStrings[MSG_WINDOW_OK_GAD];
  74.  gdata[GAD_CANCEL].name  =AppStrings[MSG_WINDOW_CANCEL_GAD];
  75.  
  76.  /* Calculate maximum label width for name string gadget */
  77.  maxw1=TextLength(&TmpRastPort,AppStrings[MSG_WINDOW_NAME_GAD],
  78.                   strlen(AppStrings[MSG_WINDOW_NAME_GAD]));
  79.  maxw1+=INTERWIDTH+REQBUTTONWIDTH;
  80.  
  81.  /* Calculate minimal string gadget width */
  82.  ww=TextLength(&TmpRastPort,AppStrings[MSG_ACCESSWIN_NEWNAME],
  83.                strlen(AppStrings[MSG_ACCESSWIN_NEWNAME]))+
  84.     maxw1+3*INTERWIDTH;
  85.  
  86.  /* Calculate width for listview gadget */
  87.  if ((tmp=ListViewColumns*ScreenFont->tf_XSize) > ww) ww=tmp;
  88.  
  89.  /* Calculate button gadgets width */
  90.  gd=&gdata[GAD_ADD];
  91.  maxw2=0;
  92.  for (i=GAD_ADD; i<=GAD_CANCEL; i++, gd++)
  93.   if ((tmp=TextLength(&TmpRastPort,gd->name,strlen(gd->name))) > maxw2)
  94.    maxw2=tmp;
  95.  maxw2+=2*INTERWIDTH;
  96.  if ((tmp=2*(maxw2+INTERWIDTH)) > ww) ww=tmp;
  97.  
  98.  /* window height */
  99.  wh=(ListViewRows+3)*fheight+5*INTERHEIGHT+2;
  100.  
  101.  /* Init gadgets */
  102.  gd=gdata;
  103.  maxw1+=left;
  104.  tmp=WindowTop+INTERHEIGHT;
  105.  
  106.  /* Name button gadget */
  107.  gd->type=GENERIC_KIND;
  108.  gd->flags=0;
  109.  gd->left=maxw1-REQBUTTONWIDTH;
  110.  gd->top=tmp;
  111.  gd->width=REQBUTTONWIDTH;
  112.  gd->height=strheight;
  113.  
  114.  /* Name text gadget */
  115.  gd++;
  116.  gd->type=TEXT_KIND;
  117.  gd->flags=PLACETEXT_LEFT;
  118.  gd->left=maxw1-REQBUTTONWIDTH;
  119.  gd->top=tmp+strheight/2;
  120.  gd->width=0;
  121.  gd->height=0;
  122.  
  123.  /* Name string gadget */
  124.  gd++;
  125.  gd->type=STRING_KIND;
  126.  gd->flags=PLACETEXT_LEFT;
  127.  gd->tags=nametags;
  128.  gd->left=maxw1;
  129.  gd->top=tmp;
  130.  gd->width=ww-maxw1-INTERWIDTH+left;
  131.  gd->height=strheight;
  132.  tmp+=strheight+fheight+INTERHEIGHT;
  133.  
  134.  /* Exec objects list gadget */
  135.  gd++;
  136.  gd->type=LISTVIEW_KIND;
  137.  gd->flags=PLACETEXT_ABOVE;
  138.  gd->tags=lvtags;
  139.  gd->left=left;
  140.  gd->top=tmp;
  141.  gd->width=ww-INTERWIDTH;
  142.  gd->height=(ListViewRows-1)*fheight;
  143.  tmp+=(ListViewRows-1)*fheight+INTERHEIGHT;
  144.  
  145.  /* Add button gadget */
  146.  maxw1=ww-maxw2-INTERWIDTH+left;
  147.  gd++;
  148.  gd->type=BUTTON_KIND;
  149.  gd->flags=PLACETEXT_IN;
  150.  gd->left=left;
  151.  gd->top=tmp;
  152.  gd->width=maxw2;
  153.  gd->height=fheight;
  154.  
  155.  /* Remove button gadget */
  156.  gd++;
  157.  gd->type=BUTTON_KIND;
  158.  gd->flags=PLACETEXT_IN;
  159.  gd->tags=DisabledTags;
  160.  gd->left=maxw1;
  161.  gd->top=tmp;
  162.  gd->width=maxw2;
  163.  gd->height=fheight;
  164.  tmp+=fheight+INTERHEIGHT;
  165.  
  166.  /* OK button gadget */
  167.  gd++;
  168.  gd->type=BUTTON_KIND;
  169.  gd->flags=PLACETEXT_IN;
  170.  gd->left=left;
  171.  gd->top=tmp;
  172.  gd->width=maxw2;
  173.  gd->height=fheight;
  174.  
  175.  /* Cancel button gadget */
  176.  gd++;
  177.  gd->type=BUTTON_KIND;
  178.  gd->flags=PLACETEXT_IN;
  179.  gd->left=maxw1;
  180.  gd->top=tmp;
  181.  gd->width=maxw2;
  182.  gd->height=fheight;
  183.  
  184.  /* Init vanilla key array */
  185.  KeyArray[KEY_NAME]  =FindVanillaKey(gdata[GAD_NAME_TXT].name);
  186.  KeyArray[KEY_ADD]   =FindVanillaKey(gdata[GAD_ADD].name);
  187.  KeyArray[KEY_OK]    =FindVanillaKey(gdata[GAD_OK].name);
  188.  KeyArray[KEY_CANCEL]=FindVanillaKey(gdata[GAD_CANCEL].name);
  189.  
  190.  /* Init dummy requester structure */
  191.  InitRequester(&DummyReq);
  192. }
  193.  
  194. /* Free Access node */
  195. void FreeAccessNode(struct Node *node)
  196. {
  197.  struct AccessNode *an=(struct AccessNode *) node;
  198.  char *s;
  199.  
  200.  if (s=an->an_Node.ln_Name) free(s);
  201.  
  202.  /* Free entries */
  203.  {
  204.   struct Node *aen1,*aen2=GetHead(&an->an_Entries);
  205.  
  206.   /* Scan list */
  207.   while (aen1=aen2) {
  208.    /* Get next node */
  209.    aen2=GetSucc(aen1);
  210.  
  211.    /* Remove node */
  212.    Remove(aen1);
  213.  
  214.    /* Free node */
  215.    if (s=aen1->ln_Name) free(s);
  216.    FreeMem(aen1,sizeof(struct Node));
  217.   }
  218.  }
  219.  /* Free Node */
  220.  FreeMem(an,sizeof(struct AccessNode));
  221. }
  222.  
  223. /* Copy entries list */
  224. static BOOL CopyEntriesList(struct List *src, struct List *dest)
  225. {
  226.  struct Node *orignode=GetHead(src);
  227.  BOOL rc=TRUE;
  228.  
  229.  /* Scan source list */
  230.  while (rc && orignode) {
  231.   struct Node *newnode;
  232.  
  233.   /* Alloc memory for new node */
  234.   if (newnode=AllocMem(sizeof(struct Node),MEMF_CLEAR|MEMF_PUBLIC)) {
  235.    /* Append new node */
  236.    AddTail(dest,newnode);
  237.  
  238.    /* Copy name */
  239.    if (orignode->ln_Name && !(newnode->ln_Name=strdup(orignode->ln_Name)))
  240.     rc=FALSE;
  241.   } else
  242.    /* Error */
  243.    rc=FALSE;
  244.  
  245.   /* Get pointer to next node */
  246.   orignode=GetSucc(orignode);
  247.  }
  248.  return(rc);
  249. }
  250.  
  251. /* Copy Access node */
  252. struct Node *CopyAccessNode(struct Node *node)
  253. {
  254.  struct AccessNode *an,*orignode=(struct AccessNode *) node;
  255.  
  256.  /* Alloc memory for Access node */
  257.  if (an=AllocMem(sizeof(struct AccessNode),MEMF_PUBLIC|MEMF_CLEAR)) {
  258.   NewList(&an->an_Entries);
  259.  
  260.   /* Got an old node? */
  261.   if (orignode) {
  262.    /* Yes, copy it */
  263.    if ((!orignode->an_Node.ln_Name || (an->an_Node.ln_Name=
  264.                                         strdup(orignode->an_Node.ln_Name))) &&
  265.        CopyEntriesList(&orignode->an_Entries,&an->an_Entries))
  266.    return(an);
  267.   } else
  268.    /* No, set defaults */
  269.    if (an->an_Node.ln_Name=strdup(AppStrings[MSG_ACCESSWIN_NEWNAME]))
  270.     /* Return pointer to new node */
  271.     return(an);
  272.  
  273.   FreeAccessNode((struct Node *) an);
  274.  }
  275.  /* Call failed */
  276.  return(NULL);
  277. }
  278.  
  279. /* Activate name string gadget */
  280. static void ActivateNameGadget(void)
  281. {
  282.  ActivateGadget(gdata[GAD_NAME_STR].gadget,w,NULL);
  283. }
  284.  
  285. /* Open access edit window */
  286. BOOL OpenAccessEditWindow(struct Node *node, struct Window *parent)
  287. {
  288.  /* Copy node */
  289.  if (CurrentNode=(struct AccessNode *) CopyAccessNode(node)) {
  290.   /* Set tags */
  291.   nametags[0].ti_Data=(ULONG) CurrentNode->an_Node.ln_Name;
  292.   lvtags[0].ti_Data=(ULONG) &CurrentNode->an_Entries;
  293.  
  294.   /* Create gadgets */
  295.   if (gl=CreateGadgetList(gdata,GADGETS)) {
  296.    /* Open window */
  297.    if (w=OpenWindowTags(NULL,WA_Left,        parent->LeftEdge,
  298.                              WA_Top,         parent->TopEdge+WindowTop,
  299.                              WA_InnerWidth,  ww,
  300.                              WA_InnerHeight, wh,
  301.                              WA_AutoAdjust,  TRUE,
  302.                              WA_Title,       AppStrings[MSG_ACCESSWIN_TITLE],
  303.                              WA_PubScreen,   PublicScreen,
  304.                              WA_Flags,       WFLG_CLOSEGADGET|WFLG_DRAGBAR|
  305.                                              WFLG_DEPTHGADGET|WFLG_RMBTRAP|
  306.                                              WFLG_ACTIVATE,
  307.                              TAG_DONE)) {
  308.     /* Init requester button gadgets */
  309.     InitReqButtonGadget(gdata[GAD_NAME_BUT].gadget);
  310.  
  311.     /* Add gadgets to window */
  312.     AddGList(w,gl,(UWORD) -1,(UWORD) -1,NULL);
  313.     RefreshGList(gl,w,NULL,(UWORD) -1);
  314.     GT_RefreshWindow(w,NULL);
  315.  
  316.     /* Activate name string gadget */
  317.     ActivateNameGadget();
  318.  
  319.     /* Set local variables */
  320.     w->UserPort=IDCMPPort;
  321.     w->UserData=(BYTE *) HandleAccessEditWindowIDCMP;
  322.     ModifyIDCMP(w,WINDOW_IDCMP);
  323.     CurrentWindow=w;
  324.     ReqOpen=FALSE;
  325.     CurrentEntry=NULL;
  326.     CurrentTop=0;
  327.     CurrentOrd=-1;
  328.  
  329.     /* All OK. */
  330.     return(TRUE);
  331.    }
  332.    FreeGadgets(gl);
  333.   }
  334.   FreeAccessNode((struct Node *) CurrentNode);
  335.  }
  336.  /* Call failed */
  337.  return(FALSE);
  338. }
  339.  
  340. /* Close access edit window */
  341. static void CloseAccessEditWindow(void)
  342. {
  343.  /* Free resources */
  344.  RemoveGList(w,gl,(UWORD) -1);
  345.  CloseWindowSafely(w);
  346.  FreeGadgets(gl);
  347. }
  348.  
  349. /* Detach list */
  350. static void DetachEntryList(void)
  351. {
  352.  GT_SetGadgetAttrs(gdata[GAD_ENTRIES].gadget,w,NULL,GTLV_Labels,-1,
  353.                                                     TAG_DONE);
  354. }
  355.  
  356. /* Attach list */
  357. static void AttachEntryList(void)
  358. {
  359.  GT_SetGadgetAttrs(gdata[GAD_ENTRIES].gadget,w,NULL,GTLV_Labels,
  360.                                                      &CurrentNode->an_Entries,
  361.                                                     GTLV_Top,      CurrentTop,
  362.                                                     GTLV_Selected, CurrentOrd,
  363.                                                     TAG_DONE);
  364. }
  365.  
  366. /* Name gadget function */
  367. static void NameGadgetFunc(void)
  368. {
  369.  /* Open library */
  370.  if (EnvoyBase=OpenLibrary("envoy.library",37)) {
  371.   char *buffer;
  372.  
  373.   /* Allocate memory for the host name buffer */
  374.   if (buffer=AllocMem(SGBUFLEN,MEMF_PUBLIC)) {
  375.  
  376.    /* Open requester */
  377.    if (HostRequest(HREQ_Buffer,   buffer,
  378.                    HREQ_BuffSize, SGBUFLEN,
  379.                    HREQ_Title,    AppStrings[MSG_HOSTREQ_TITLE],
  380.                    TAG_DONE))
  381.     /* User selected a name, put name into name string gadget */
  382.     GT_SetGadgetAttrs(gdata[GAD_NAME_STR].gadget,w,NULL,GTST_String,buffer,
  383.                                                         TAG_DONE);
  384.  
  385.    /* Free memory */
  386.    FreeMem(buffer,SGBUFLEN);
  387.   }
  388.  
  389.   /* Close library */
  390.   CloseLibrary(EnvoyBase);
  391.  }
  392. }
  393.  
  394. /* Add gadget function */
  395. static void AddGadgetFunc(void)
  396. {
  397.  if (!ReqOpen) {
  398.   /* Open list requester */
  399.   if (OpenListRequester(TMOBJTYPE_EXEC,w)) {
  400.    /* Disable window */
  401.    DisableWindow(w,&DummyReq);
  402.  
  403.    /* Detach entry list */
  404.    DetachEntryList();
  405.  
  406.    /* Set update function */
  407.    UpdateWindow=UpdateAccessEditWindow;
  408.    ReqOpen=TRUE;
  409.   }
  410.  }
  411. }
  412.  
  413. static struct Node *OKGadgetFunc(void)
  414. {
  415.  struct Node *rc;
  416.  char *s;
  417.  
  418.  /* Free old string */
  419.  if (s=CurrentNode->an_Node.ln_Name) free(s);
  420.  CurrentNode->an_Node.ln_Name=NULL;
  421.  
  422.  /* Duplicate new string */
  423.  if ((s=CurrentNode->an_Node.ln_Name=
  424.        DuplicateBuffer(gdata[GAD_NAME_STR].gadget)) != (char *) -1) {
  425.   ULONG len=strlen(s)-1;
  426.  
  427.   /* Strip trailing ':' */
  428.   if ((len>=0) && (s[len]==':')) s[len]='\0';
  429.  
  430.   rc=(struct Node *) CurrentNode;
  431.  } else {
  432.   /* Couldn't copy string */
  433.   rc=(struct Node *) -1;
  434.   FreeAccessNode((struct Node *) CurrentNode);
  435.  }
  436.  return(rc);
  437. }
  438.  
  439. /* Handle access edit window IDCMP events */
  440. void *HandleAccessEditWindowIDCMP(struct IntuiMessage *msg)
  441. {
  442.  struct Node *NewNode=NULL;
  443.  
  444.  /* Which IDCMP class? */
  445.  switch (msg->Class) {
  446.   case IDCMP_CLOSEWINDOW:   NewNode=(struct Node *) -1;
  447.                             FreeAccessNode((struct Node *) CurrentNode);
  448.                             break;
  449.   case IDCMP_REFRESHWINDOW: GT_BeginRefresh(w);
  450.                             GT_EndRefresh(w,TRUE);
  451.                             break;
  452.   case IDCMP_GADGETUP:
  453.    switch (((struct Gadget *) msg->IAddress)->GadgetID) {
  454.     case GAD_NAME_BUT: NameGadgetFunc();
  455.                        break;
  456.     case GAD_ENTRIES:  {
  457.                         ULONG i;
  458.  
  459.                         /* Find node */
  460.                         CurrentTop=(msg->Code>ListViewRows-4) ?
  461.                          msg->Code-ListViewRows+4 : 0;
  462.                         CurrentOrd=msg->Code;
  463.                         CurrentEntry=GetHead(&CurrentNode->an_Entries);
  464.                         for (i=0; i<CurrentOrd; i++)
  465.                          CurrentEntry=GetSucc(CurrentEntry);
  466.  
  467.                         /* Activate remove gadget */
  468.                         DisableGadget(gdata[GAD_REMOVE].gadget,w,FALSE);
  469.                        }
  470.                        break;
  471.     case GAD_ADD:      AddGadgetFunc();
  472.                        break;
  473.     case GAD_REMOVE:   if (CurrentEntry) {
  474.                         char *s;
  475.  
  476.                         /* Detach entry list */
  477.                         DetachEntryList();
  478.  
  479.                         /* Disable remove gadget */
  480.                         DisableGadget(gdata[GAD_REMOVE].gadget,w,TRUE);
  481.  
  482.                         /* Remove node */
  483.                         Remove(CurrentEntry);
  484.  
  485.                         /* Free node */
  486.                         if (s=CurrentEntry->ln_Name) free(s);
  487.                         FreeMem(CurrentEntry,sizeof(struct Node));
  488.  
  489.                         /* Reset pointers */
  490.                         CurrentEntry=NULL;
  491.                         if (CurrentTop) CurrentTop--;
  492.                         CurrentOrd=-1;
  493.  
  494.                         /* Attach entry list */
  495.                         AttachEntryList();
  496.                        }
  497.                        break;
  498.     case GAD_OK:       NewNode=OKGadgetFunc();
  499.                        break;
  500.     case GAD_CANCEL:   NewNode=(struct Node *) -1;
  501.                        FreeAccessNode((struct Node *) CurrentNode);
  502.                        break;
  503.    }
  504.    break;
  505.   case IDCMP_VANILLAKEY:
  506.    switch (MatchVanillaKey(msg->Code,KeyArray)) {
  507.     case KEY_NAME:   NameGadgetFunc();
  508.                      break;
  509.     case KEY_ADD:    AddGadgetFunc();
  510.                      break;
  511.     case KEY_OK:     NewNode=OKGadgetFunc();
  512.                      break;
  513.     case KEY_CANCEL: NewNode=(struct Node *) -1;
  514.                      FreeAccessNode((struct Node *) CurrentNode);
  515.                      break;
  516.    }
  517.    break;
  518.  }
  519.  
  520.  /* Close window? */
  521.  if (NewNode) {
  522.   /* Yes. But first reply message!!! */
  523.   GT_ReplyIMsg(msg);
  524.   CloseAccessEditWindow();
  525.  }
  526.  
  527.  return(NewNode);
  528. }
  529.  
  530. /* Update dock edit window */
  531. void UpdateAccessEditWindow(void *data)
  532. {
  533.  /* Got data? */
  534.  if (data != LREQRET_CANCEL) {
  535.   char *new;
  536.  
  537.   /* Selected something? */
  538.   if (new=(data == LREQRET_NOSELECT) ? NULL : ((struct Node *) data)
  539.        ->ln_Name) {
  540.    /* Yes, create new node */
  541.    struct Node *aen;
  542.  
  543.    /* Create dummy tool */
  544.    if (aen=AllocMem(sizeof(struct Node),MEMF_PUBLIC|MEMF_CLEAR))
  545.  
  546.     /* Copy name string */
  547.     if (aen->ln_Name=strdup(new)) {
  548.  
  549.      /* Insert after selected node? */
  550.      if (CurrentEntry) {
  551.       /* Yes */
  552.       Insert(&CurrentNode->an_Entries,aen,CurrentEntry);
  553.       CurrentOrd++;
  554.       CurrentTop=(CurrentOrd>ListViewRows-4) ? CurrentOrd-ListViewRows+4 : 0;
  555.      } else {
  556.       /* No */
  557.       struct Node *tmpnode;
  558.       ULONG i;
  559.  
  560.       /* Add node to the end of list */
  561.       AddTail(&CurrentNode->an_Entries,aen);
  562.  
  563.       /* Search ordinal number */
  564.       tmpnode=GetHead(&CurrentNode->an_Entries);
  565.       for (i=0; tmpnode; i++) tmpnode=GetSucc(tmpnode);
  566.       CurrentOrd=--i;
  567.       CurrentTop=(i>ListViewRows-4) ? i-ListViewRows+4 : 0;
  568.      }
  569.      CurrentEntry=aen;
  570.  
  571.      /* Activate remove gadget */
  572.      DisableGadget(gdata[GAD_REMOVE].gadget,w,FALSE);
  573.     } else
  574.      /* Error */
  575.      FreeMem(aen,sizeof(struct Node));
  576.   }
  577.  }
  578.  
  579.  /* Attach entry list */
  580.  AttachEntryList();
  581.  
  582.  /* Enable window */
  583.  EnableWindow(w,&DummyReq,WINDOW_IDCMP);
  584.  
  585.  /* Restore update function pointer */
  586.  UpdateWindow=UpdateMainWindow;
  587.  CurrentWindow=w;
  588.  ReqOpen=FALSE;
  589. }
  590.  
  591. /* Read TMAC IFF chunk into Access node */
  592. struct Node *ReadAccessNode(UBYTE *buf)
  593. {
  594.  struct AccessNode *an;
  595.  
  596.  /* Allocate memory for node */
  597.  if (an=AllocMem(sizeof(struct AccessNode),MEMF_PUBLIC|MEMF_CLEAR)) {
  598.   struct AccessPrefsObject *apo=(struct AccessPrefsObject *) buf;
  599.   ULONG sbits=apo->apo_StringBits;
  600.   UBYTE *ptr=(UBYTE *) &apo[1];
  601.  
  602.   if (!(sbits & DOPO_NAME) || (an->an_Node.ln_Name=GetConfigStr(&ptr))) {
  603.    LONG entries=0;
  604.    UBYTE enflags;
  605.  
  606.    /* Init list */
  607.    NewList(&an->an_Entries);
  608.  
  609.    /* Get tools */
  610.    while ((enflags=*ptr++) & AOPOE_CONTINUE) {
  611.     struct Node *aen;
  612.  
  613.     if (aen=AllocMem(sizeof(struct Node),MEMF_PUBLIC|MEMF_CLEAR)) {
  614.      /* Add tool to list */
  615.      AddTail(&an->an_Entries,aen);
  616.  
  617.      if (!(enflags & AOPOE_EXEC) || (aen->ln_Name=GetConfigStr(&ptr)))
  618.       /* All OK. */
  619.       entries++;
  620.      else {
  621.       /* Error */
  622.       entries=-1;
  623.       break;
  624.      }
  625.     } else {
  626.      /* No memory. */
  627.      entries=-1;
  628.      break;
  629.     }
  630.    }
  631.  
  632.    /* Error? All OK. */
  633.    if (entries!=-1) return(an);
  634.   }
  635.  
  636.   /* Call failed */
  637.   FreeAccessNode((struct Node *) an);
  638.  }
  639.  return(NULL);
  640. }
  641.  
  642. /* Write Access node to TMAC IFF chunk */
  643. BOOL WriteAccessNode(struct IFFHandle *iff, UBYTE *buf, struct Node *node)
  644. {
  645.  struct AccessNode *an=(struct AccessNode *) node;
  646.  struct AccessPrefsObject *apo=(struct AccessPrefsObject *) buf;
  647.  ULONG sbits=0;
  648.  UBYTE *ptr=(UBYTE *) &apo[1];
  649.  
  650.  /* Copy strings */
  651.  if (PutConfigStr(an->an_Node.ln_Name,&ptr)) sbits|=AOPO_NAME;
  652.  
  653.  /* set string bits */
  654.  apo->apo_StringBits=sbits;
  655.  
  656.  /* Write entry list */
  657.  {
  658.   struct Node *aen=GetHead(&an->an_Entries);
  659.  
  660.   while (aen) {
  661.    UBYTE *flptr=ptr++;
  662.    UBYTE aefl=AOPOE_CONTINUE;
  663.  
  664.    if (PutConfigStr(aen->ln_Name,&ptr)) aefl|=AOPOE_EXEC;
  665.  
  666.    /* Put flags */
  667.    *flptr=aefl;
  668.  
  669.    /* Get next node */
  670.    aen=GetSucc(aen);
  671.   }
  672.  }
  673.  
  674.  /* Append terminator */
  675.  *ptr++=0;
  676.  
  677.  /* calculate length */
  678.  sbits=ptr-buf;
  679.  
  680.  DEBUG_PRINTF("chunk size %ld\n",sbits);
  681.  
  682.  /* Open chunk */
  683.  if (PushChunk(iff,0,ID_TMAC,sbits)) return(FALSE);
  684.  
  685.  /* Write chunk */
  686.  if (WriteChunkBytes(iff,buf,sbits)!=sbits) return(FALSE);
  687.  
  688.  /* Close chunk */
  689.  if (PopChunk(iff)) return(FALSE);
  690.  
  691.  /* All OK. */
  692.  return(TRUE);
  693. }
  694.